/*
   Copyright (c) [Year] [name of copyright holder]
   [Software Name] is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details.  
*/

#ifndef JIAJIA_LING_HPP
#define JIAJIA_LING_HPP

#include"jiajiastd.hpp"
#include"arg.hpp"
#include"jjir.hpp"

namespace jiajia{

    // 赋值
    static msg_t ASSIGN(value_t * rhs, value_t * result){
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        enum_t t = rhs->getType();
        if(t == value_t::INVALIDTYPE) return msg::rhs_invaild_err;

        (*result).set(*rhs);

        return msg::success;
    }

    // 取相反数
    static msg_t MINUS(value_t * rhs, value_t * result){
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        enum_t t = rhs->getType();
        if(t == value_t::INVALIDTYPE) return msg::rhs_invaild_err;
        if(t != value_t::REALTYPE) return msg::rhs_real_err;

        result->setReal(-(rhs->getReal()));

        return msg::success;
    }

    // 取反
    static msg_t NO(value_t * rhs, value_t * result){
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        enum_t t = rhs->getType();
        if(t == value_t::INVALIDTYPE) return msg::rhs_invaild_err;
        if(t != value_t::BOOLTYPE) return msg::rhs_bool_err;

        result->setBool(!(rhs->getBool()));

        return msg::success;
    }

    // 强制转成 bool 值
    static msg_t TOBOOL(value_t * rhs, value_t * result){
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        bool flag = false;
        if(rhs->toBool(flag) == false) return msg::tobool_err;
        result->setBool(flag);
        return msg::success;
    }

    // 字符串运算
    static msg_t LINK(value_t * lhs, value_t * rhs, value_t * result){
        if(lhs == nullptr) return msg::lhs_null_err;
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        enum_t t1 = lhs->getType();
        enum_t t2 = rhs->getType();
        if(t1 == value_t::INVALIDTYPE) return msg::lhs_invaild_err;
        if(t2 == value_t::INVALIDTYPE) return msg::rhs_invaild_err;
        if(t1 != value_t::STRINGTYPE) return msg::lhs_string_err;
        if(t2 != value_t::STRINGTYPE) return msg::rhs_string_err;

        std::string s;
        lhs->toString(s);
        rhs->toString(s);
        
        result->setStr(std::move(my::ustring(s)));

        return msg::success;
    }

    // 数值运算
    static msg_t REALOP(code_t code, value_t * lhs, value_t * rhs, value_t * result){
        if(lhs == nullptr) return msg::lhs_null_err;
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        enum_t t1 = lhs->getType();
        enum_t t2 = rhs->getType();
        if(t1 == value_t::INVALIDTYPE) return msg::lhs_invaild_err;
        if(t2 == value_t::INVALIDTYPE) return msg::rhs_invaild_err;
        if(t1 != value_t::REALTYPE) return msg::lhs_real_err;
        if(t2 != value_t::REALTYPE) return msg::rhs_real_err;

        real_t ret = 0.0;
        switch(code){
        case code::ADD: ret = lhs->getReal() + rhs->getReal(); break;
        case code::SUB: ret = lhs->getReal() - rhs->getReal(); break;
        case code::MULT: ret = lhs->getReal() * rhs->getReal(); break;
        case code::DEV: ret = lhs->getReal() / rhs->getReal(); break;
        default: break;
        }
        result->setReal(ret);
        return msg::success;        
    }

    // 比较运算
    static msg_t BOOLOP(code_t code, value_t * lhs, value_t * rhs, value_t * result){
        if(lhs == nullptr) return msg::lhs_null_err;
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        enum_t t1 = lhs->getType();
        enum_t t2 = rhs->getType();
        if(t1 == value_t::INVALIDTYPE) return msg::lhs_invaild_err;
        if(t2 == value_t::INVALIDTYPE) return msg::rhs_invaild_err;
        if(t1 != t2) return msg::lr_typene_err;

        int ret = value_t::comp(*lhs, *rhs);
        switch(code){
        case code::EQ: result->setBool(ret == 0); break;
        case code::NE: result->setBool(ret != 0); break;
        case code::GT: result->setBool(ret > 0); break;
        case code::LT: result->setBool(ret < 0); break;
        case code::GE: result->setBool(ret >= 0); break;
        case code::LE: result->setBool(ret <= 0); break;
        default: break;
        }

        return msg::success;
    }

    // 数组压入一个
    static msg_t PUSH(value_t * lhs, value_t * result){
        if(lhs == nullptr) return msg::lhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        if(lhs->getType() == value_t::INVALIDTYPE){
            my::allocstack ac;
            lhs->setSeq(mem::salloc<seq_t>(ac, 1));
        }

        if(lhs->getType() != value_t::SEQTYPE) return msg::lhs_seq_err;

        seq_t & seq = lhs->getSeq();
        seq.chsize(1);
        result->refto(&seq[-1]);
        return msg::success;
    }

    // 数组索引操作
    static msg_t AT(value_t * lhs, value_t * rhs, value_t * result){
        if(lhs == nullptr) return msg::lhs_null_err;
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        if(lhs->getType() != value_t::SEQTYPE) return msg::lhs_seq_err;
        if(rhs->getType() != value_t::REALTYPE) return msg::rhs_real_err;

        double index = 0.0;
        double mod = std::modf(rhs->getReal(), &index);
        if(mod != 0.0) return msg::at_num_err;
        seq_t & seq = lhs->getSeq();
        if(index < 1.0 || index > (real_t)seq.size()) return msg::at_outrange_err;

        result->refto(&(seq[((long)index)-1]));
        return msg::success;
    }

    // 在 jiajia 语法当中，‘的’其实有插入的操作的，比如小明的年龄 = 10；
    // 此时如果小明并没有年龄的属性，则会向小明变量中插入年龄的属性。
    // 所以需要判断右值和左值的区别。

    // 用于表的 ‘的’插入 操作，比如小明的年龄 = 10;属于左值操作。
    static msg_t INSERT(table_t * lhs, string_t * rhs, value_t * result){
        result->refto(lhs->insertValue(*rhs));
        return msg::success;
    }

    // 用于表的 ‘的’查找 操作，比如小明的年龄 = 10;属于右值操作。
    static msg_t FIND(table_t * lhs, string_t * rhs, value_t * result){
        // 如果 lhs 是一个表，则直接查找
        value_t * val = lhs->findValue(*rhs);
        if(val == nullptr) return msg::find_null_err;

        result->refto(val);

        return msg::success;
    }

    static msg_t TABLEOP(code_t code, value_t * lhs, string_t * rhs, value_t * result){
        if(lhs == nullptr) return msg::lhs_null_err;
        if(rhs == nullptr) return msg::rhs_null_err;
        if(result == nullptr) return msg::result_null_err;

        enum_t t = lhs->getType();
        if(t == value_t::INVALIDTYPE){
            my::allocstack ac;
            // 如果 lhs 还是一个未知的类型，证明他是一个刚创建的变量，则把它类型设置为表
            lhs->setTable(mem::salloc<table_t>(ac, 1));
        }

        if(lhs->getType() != value_t::TABLETYPE) return msg::lhs_table_err;

        switch(code){
        case code::FIND: FIND(&(lhs->getTable()), rhs, result); break;
        case code::INSERT: INSERT(&(lhs->getTable()), rhs, result); break;
        default: break;
        }

        return msg::success;
    }

    // 函数调用
    static msg_t ARGNEW(jjcallstack & stack){
        stack.newArgs();
        return msg::success;
    }

    static msg_t ARGPUSH(jjcallstack & stack, value_t * val){
        if(val == nullptr) return msg::rhs_null_err;
        stack.pushArg(val);
        return msg::success;
    }

    static msg_t CALL(func_t fpt, jjcallstack & stack, value_t * result){
        if(result == nullptr) return msg::result_null_err;
        msg_t m = (*fpt)(stack.args(), stack.nums(), result);
        stack.popArgs();
        return m;
    }

    // 关于跳转的函数
    static msg_t IF(code_t code, value_t * expr, jjirnode * goto_ir, jjirnode ** next){
        if(expr == nullptr) return msg::if_expr_null_err;
        if(goto_ir == nullptr) return msg::goto_null_err;

        bool flag;
        switch(expr->getType()){
        case value_t::INVALIDTYPE: flag = false; break;
        case value_t::BOOLTYPE: flag = expr->getBool(); break;
        case value_t::REALTYPE: flag = expr->getReal() != 0.0; break;
        default: return msg::tobool_err;
        }

        if((code == code::IFFALSE && flag == false) || (code == code::IFTRUE && flag == true)){
            *next = goto_ir;
        }

        return msg::success;
    }

    static msg_t GOTO(jjirnode * goto_ir, jjirnode ** next){
        if(goto_ir == nullptr) return msg::goto_null_err;
        *next = goto_ir;
        return msg::success;
    }
}

#endif
